
__doc__ = """
                ####################################
                        BladeProxy 0.1.0
                This tool will help u in injection
                when some keywords
                are blocked by web defense system.

                made by: nessus@yahoo.cn

                usage:BladeProxy.py <port> <encodenum>
                encodenum:
                0:not encode
                1:assic encode
                2:unicode encode
                3:%% encode
                #####################################

"""

__version__ = "1.0"
encode_way = 0
#send_way = 0
senwords =['and',
              'select',
              'union',
              'declare',
              "'",
              'char',
              'exists',
              'insert',
              'create',
              'drop'
              ]

import BaseHTTPServer, select, socket, SocketServer, urlparse,re,sys

class ProxyHandler (BaseHTTPServer.BaseHTTPRequestHandler):
    __base = BaseHTTPServer.BaseHTTPRequestHandler
    __base_handle = __base.handle

    server_version = "BladeProxy/" + __version__
    rbufsize = 0                        # self.rfile Be unbuffered

    def handle(self):
        (ip, port) =  self.client_address
        if hasattr(self, 'allowed_clients') and ip not in self.allowed_clients:
            self.raw_requestline = self.rfile.readline()
            if self.parse_request(): self.send_error(403)
        else:
            self.__base_handle()

    def _connect_to(self, netloc, soc):
        i = netloc.find(':')
        if i >= 0:
            host_port = netloc[:i], int(netloc[i+1:])
        else:
            host_port = netloc, 80
        #print "\t" "connect to %s:%d" % host_port
        try:
            soc.connect(host_port)
        except socket.error, arg:
            try: msg = arg[1]
            except: msg = arg
            self.send_error(404, msg)
            return 0
        return 1

    def do_CONNECT(self):
        soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            if self._connect_to(self.path, soc):
                self.log_request(200)
                self.wfile.write(self.protocol_version +" 200 Connection established\r\n")
                self.wfile.write("Proxy-agent: %s\r\n" % self.version_string())
                self.wfile.write("\r\n")
                self._read_write(soc, 300)
        finally:
            #print "\t" "bye"
            soc.close()
            self.connection.close()

    
    def do_encode(self, word):
        global encode_method
        if encode_method == 'ascii':
            return self.ascii_encode(word)
        elif encode_method == 'unicode':
            return self.unicode_encode(word)
        elif encode_method == 'no':
            return word
        
    def query_transform(self,query):
        global keyword_list
        for keyword in keyword_list:
            if re.search(keyword,query) != None:
                new_keyword = self.do_encode(keyword)
                query.replace(keyword,new_keyword)
        return query

    def header_transform(self, headers):
        global header_list
        for item in header_list:
            pair = item.split("====>")
            if pair[0] != '' and pair[1] == '':
                del headers[str(pair[0])]
            elif pair[0] != '' and pair[1] != '':
                headers[str(pair[0])] = str(pair[1])
        return headers
    
    def ascii_encode(self,s):
        ss = lambda s: ''.join(map(lambda c:"%%%X"%ord(c),s))
        return ss(s)

    def unicode_encode(self,s):
        ss = lambda s: ''.join(map(lambda c:"%%u00%X"%ord(c),s))
        return ss(s)

    
    def do_POST(self):
        (scm, netloc, path, params, query, fragment) = urlparse.urlparse(self.path, 'http')

        if self.command == 'POST' and not self.headers.has_key('content-length'):
            self.error(400, "Missing Content-Length for POST method")
        
        length = int(self.headers.get('content-length', 0))
        #print 'lenth is'+ self.headers['content-length']
        if length >0:
            content = self.rfile.read(length)
            content = self.query_transform(content)
            self.headers = self.header_transform(self.headers)
            self.headers['content-length'] = repr(len(content))
            
        soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            if self._connect_to(netloc, soc):
                self.log_request()
                soc.send("%s %s %s\r\n" % (
                    self.command,
                    urlparse.urlunparse(('', '', path, params, '', '')),
                    self.request_version))
                self.headers['Connection'] = 'close'
                del self.headers['Proxy-Connection']
                for key_val in self.headers.items():
                    soc.send("%s: %s\r\n" % key_val)
                soc.send("\r\n")
                soc.send(content)
                self._read_write(soc)
        finally:
            #print "\t" "bye"
            soc.close()
            self.connection.close()
   
    def do_GET(self):
        (scm, netloc, path, params, query, fragment) = urlparse.urlparse(self.path, 'http')
        if query:
            query = self.query_transform(query)
        
        if scm != 'http' or fragment or not netloc:
            self.send_error(400, "bad url %s" % self.path)
            return

        self.headers = self.header_transform(self.headers)
        
        soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            if self._connect_to(netloc, soc):
                self.log_request()
                soc.send("%s %s %s\r\n" % (
                    self.command,
                    urlparse.urlunparse(('', '', path, params, query, '')),
                    self.request_version))
                self.headers['Connection'] = 'close'
                del self.headers['Proxy-Connection']

                for key_val in self.headers.items():
                    soc.send("%s: %s\r\n" % key_val)
                soc.send("\r\n")
                self._read_write(soc)
        finally:
            #print "\t" "bye"
            soc.close()
            self.connection.close()

    def _read_write(self, soc, max_idling=20):
        iw = [self.connection, soc]
        ow = []
        count = 0
        while 1:
            count += 1
            (ins, _, exs) = select.select(iw, ow, iw, 3)
            if exs: break
            if ins:
                for i in ins:
                    if i is soc:
                        out = self.connection
                    else:
                        out = soc
                    data = i.recv(8192)
                    if data:
                        out.send(data)
                        count = 0
            else:
                print "\t" "idle", count
            if count == max_idling: break

    do_HEAD = do_GET
    #do_POST = do_GET
    do_PUT  = do_GET
    do_DELETE=do_GET

class ThreadingHTTPServer (SocketServer.ThreadingMixIn,
                           BaseHTTPServer.HTTPServer): pass


def readconfig():
    global encode_method, keyword_list, header_list
    method_flag = 0
    keyword_flag = 0
    header_flag = 0
    
    p = open("config.conf",'r')
    for line in p.readlines():
        ln = line.replace("\n","")
        if (ln == "[URL_KEYWORD]"):
            keyword_flag = 1
            method_flag = 0
            header_flag = 0
        elif (ln == "[ENCODE_METHOD]"):
            keyword_flag = 0
            method_flag = 1
            header_flag = 0
        elif (ln == "[HEADER]"):
            keyword_flag = 0
            method_flag = 0
            header_flag = 1
        else:
            if (keyword_flag == 1):
                keyword_list.append(ln)
            elif (method_flag == 1):
                encode_method = str(ln)
            elif (header_flag == 1):
                header_list.append(ln)
    return True

encode_method = 'no'
keyword_list = []
header_list = []

if __name__ == '__main__':
    if len(sys.argv) == 1:
        print __doc__
    elif len(sys.argv)== 3:
        SUCCESS = readconfig()
        if (SUCCESS):
            print encode_method
            print keyword_list
            print header_list

        print "Any clients will be served..."
        BaseHTTPServer.test(ProxyHandler, ThreadingHTTPServer)
